/*
 ------------------------------------------------------------------------------
 Copyright (C) 1996-2001 Id Software, Inc.

 This file is part of the Quake source code.

 The Quake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// rect.h - rectangle math library
//


#ifndef __MATH_RECT_H__
#define __MATH_RECT_H__


// Rect indices
#define LEFT						0
#define TOP							1
#define RIGHT						2
#define BOTTOM						3

extern glqRect		rect_empty;

class glqRect {
public:
	short			x1;
	short			y1;
	short			x2;
	short			y2;

public:
					glqRect (void);
	explicit		glqRect (const short x1, const short y1, const short x2, const short y2);

	short			operator [] (const int index) const;
	short &			operator [] (const int index);

	glqRect &		operator = (const glqRect &rect);
	bool			operator == (const glqRect &rect) const;
	bool			operator != (const glqRect &rect) const;

	bool			Compare (const glqRect &rect) const;
	void			Set (const short x1, const short y1, const short x2, const short y2);
	void			SetFloat (const float x1, const float y1, const float x2, const float y2);
	void			Clear (void);
	bool			IsCleared (void) const;
	void			Zero (void);
	bool			IsZeroed (void) const;
	void			AddRect (const glqRect &rect);
	void			AddPoint (const short x, const short y);
	glqRect			Expand (const short size) const;
	void			ExpandSelf (const short size);
	glqRect			Translate (const short x, const short y) const;
	void			TranslateSelf (const short x, const short y);
	void			Clip (const glqRect &rect);
	void			Clip (const glqRect &rect1, const glqRect &rect2);
	void			Combine (const glqRect &rect);
	void			Combine (const glqRect &rect1, const glqRect &rect2);
	bool			IntersectsRect (const glqRect &rect) const;
	bool			ContainsPoint (const short x, const short y) const;

	short			X (void) const;
	short			Y (void) const;
	short			Width (void) const;
	short			Height (void) const;

	int				Size (void) const;

	void			ToBounds (glqBounds &bounds) const;
	void			FromBounds (const glqBounds &bounds);

	const short *	ToShortPtr (void) const;
	short *			ToShortPtr (void);

	const char *	ToString (void) const;
};

INLINE glqRect::glqRect (void){

}

INLINE glqRect::glqRect (const short x1, const short y1, const short x2, const short y2){

	this->x1 = x1;
	this->y1 = y1;
	this->x2 = x2;
	this->y2 = y2;
}

INLINE short glqRect::operator [] (const int index) const {

	return (&x1)[index];
}

INLINE short &glqRect::operator [] (const int index){

	return (&x1)[index];
}

INLINE glqRect &glqRect::operator = (const glqRect &rect){

	x1 = rect.x1;
	y1 = rect.y1;
	x2 = rect.x2;
	y2 = rect.y2;

	return *this;
}

INLINE bool glqRect::operator == (const glqRect &rect) const {

	if (x1 != rect.x1 || y1 != rect.y1 || x2 != rect.x2 || y2 != rect.y2)
		return false;

	return true;
}

INLINE bool glqRect::operator != (const glqRect &rect) const {

	if (x1 == rect.x1 && y1 == rect.y1 && x2 == rect.x2 && y2 == rect.y2)
		return false;

	return true;
}

INLINE bool glqRect::Compare (const glqRect &rect) const {

	if (x1 != rect.x1 || y1 != rect.y1 || x2 != rect.x2 || y2 != rect.y2)
		return false;

	return true;
}

INLINE void glqRect::Set (const short x1, const short y1, const short x2, const short y2){

	this->x1 = x1;
	this->y1 = y1;
	this->x2 = x2;
	this->y2 = y2;
}

INLINE void glqRect::SetFloat (const float x1, const float y1, const float x2, const float y2){

	this->x1 = glqMath::FloatToShort(x1);
	this->y1 = glqMath::FloatToShort(y1);
	this->x2 = glqMath::FloatToShort(x2);
	this->y2 = glqMath::FloatToShort(y2);
}

INLINE void glqRect::Clear (void){

	x1 = y1 = 32767;
	x2 = y2 = -32768;
}

INLINE bool glqRect::IsCleared (void) const {

	if (x1 <= x2 || y1 <= y2)
		return false;

	return true;
}

INLINE void glqRect::Zero (void){

	x1 = y1 = 0;
	x2 = y2 = 0;
}

INLINE bool glqRect::IsZeroed (void) const {

	if (x1 != 0 || y1 != 0)
		return false;
	if (x2 != 0 || y2 != 0)
		return false;

	return true;
}

INLINE void glqRect::AddRect (const glqRect &rect){

	if (rect.x1 < x1)
		x1 = rect.x1;
	if (rect.y1 < y1)
		y1 = rect.y1;

	if (rect.x2 > x2)
		x2 = rect.x2;
	if (rect.y2 > y2)
		y2 = rect.y2;
}

INLINE void glqRect::AddPoint (const short x, const short y){

	if (x < x1)
		x1 = x;
	if (y < y1)
		y1 = y;

	if (x > x2)
		x2 = x;
	if (y > y2)
		y2 = y;
}

INLINE glqRect glqRect::Expand (const short size) const {

	return glqRect(x1 - size, y1 - size, x2 + size, y2 + size);
}

INLINE void glqRect::ExpandSelf (const short size){

	x1 -= size;
	y1 -= size;
	x2 += size;
	y2 += size;
}

INLINE glqRect glqRect::Translate (const short x, const short y) const {

	return glqRect(x1 + x, y1 + y, x2 + x, y2 + y);
}

INLINE void glqRect::TranslateSelf (const short x, const short y){

	x1 += x;
	y1 += y;
	x2 += x;
	y2 += y;
}

INLINE void glqRect::Clip (const glqRect &rect){

	x1 = Max(x1, rect.x1);
	y1 = Max(y1, rect.y1);
	x2 = Min(x2, rect.x2);
	y2 = Min(y2, rect.y2);
}

INLINE void glqRect::Clip (const glqRect &rect1, const glqRect &rect2){

	x1 = Max(rect1.x1, rect2.x1);
	y1 = Max(rect1.y1, rect2.y1);
	x2 = Min(rect1.x2, rect2.x2);
	y2 = Min(rect1.y2, rect2.y2);
}

INLINE void glqRect::Combine (const glqRect &rect){

	x1 = Min(x1, rect.x1);
	y1 = Min(y1, rect.y1);
	x2 = Max(x2, rect.x2);
	y2 = Max(y2, rect.y2);
}

INLINE void glqRect::Combine (const glqRect &rect1, const glqRect &rect2){

	x1 = Min(rect1.x1, rect2.x1);
	y1 = Min(rect1.y1, rect2.y1);
	x2 = Max(rect1.x2, rect2.x2);
	y2 = Max(rect1.y2, rect2.y2);
}

INLINE bool glqRect::IntersectsRect (const glqRect &rect) const {

	if (x1 > rect.x2 || y1 > rect.y2)
		return false;
	if (x2 < rect.x1 || y2 < rect.y1)
		return false;

	return true;
}

INLINE bool glqRect::ContainsPoint (const short x, const short y) const {

	if (x1 > x || y1 > y)
		return false;
	if (x2 < x || y2 < y)
		return false;

	return true;
}

INLINE short glqRect::X (void) const {

	return x1;
}

INLINE short glqRect::Y (void) const {

	return y1;
}

INLINE short glqRect::Width (void) const {

	if (x1 > x2)
		return 0;

	return x2 - x1;
}

INLINE short glqRect::Height (void) const {

	if (y1 > y2)
		return 0;

	return y2 - y1;
}

INLINE int glqRect::Size (void) const {

	if (x1 > x2 || y1 > y2)
		return 0;

	return (x2 - x1) * (y2 - y1);
}

INLINE const short * glqRect::ToShortPtr (void) const {

	return &x1;
}

INLINE short *glqRect::ToShortPtr (void){

	return &x1;
}


#endif	// __MATH_RECT_H__